package com.lyy.lottery.service.impl;
import java.util.Date;

import com.lyy.lottery.service.enums.ActivityPrizeStatusEnum;
import com.lyy.lottery.service.enums.ActivityPrizeTiersEnum;

import com.lyy.lottery.common.errorcode.ServiceErrorCodeConstants;
import com.lyy.lottery.common.util.JacksonUtil;
import com.lyy.lottery.common.util.RedisUtil;
import com.lyy.lottery.controller.param.DrawPrizeParam;

import com.lyy.lottery.controller.param.ShowWinningRecordsParm;
import com.lyy.lottery.dao.dataobject.*;
import com.lyy.lottery.dao.mapper.*;
import com.lyy.lottery.service.DrawPrizeService;
import com.lyy.lottery.service.dto.WinningRecordDTO;
import com.lyy.lottery.service.enums.ActivityStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;

import static com.lyy.lottery.common.config.DirectRabbitConfig.EXCHANGE_NAME;
import static com.lyy.lottery.common.config.DirectRabbitConfig.ROUTING;

@Service
@Slf4j
public class DrawPrizeServiceImpl implements DrawPrizeService {

    private final String WINNING_RECORDS_PREFIX = "WINNING_RECORDS_";
    private final Long WINNING_RECORDS_TIMEOUT = 60 * 60 * 24 * 2L;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ActivityMapper activityMapper;
    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PrizeMapper prizeMapper;
    @Autowired
    private WinningRecordMapper winningRecordMapper;
    @Autowired
    private RedisUtil redisUtil;

    //异步抽奖，接⼝只做奖品数校验即可返回
    @Override
    public void drawPrize(DrawPrizeParam param) {
        //构建消息体
        Map<String,String> map=new HashMap<>();
        map.put("messageId",String.valueOf(UUID.randomUUID()));
        map.put("messageData", JacksonUtil.writeValueAsString(param));
        //将消息携带绑定键值：DirectRouting 发送到交换机 DirectExchange
        rabbitTemplate.convertAndSend(EXCHANGE_NAME,ROUTING,map);
        log.info("mq消息发送成功：map:{}",JacksonUtil.writeValueAsString(map));
    }

    @Override
    public boolean checkDrawPrizeParam(DrawPrizeParam param) {
        //活动是否存在、是否有效
        ActivityDo activityDo=activityMapper.selectById(param.getActivityId());
        if (null == activityDo){
            log.info("校验抽奖请求不通过！原因：{}", ServiceErrorCodeConstants.ACTIVITY_IS_EMPTY.getMsg());
            return false;
        }
        if (activityDo.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())){
            log.info("校验抽奖请求不通过！原因：{}",ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED.getMsg());
            return false;
        }

        //奖品是否存在、是否有效
        ActivityPrizeDo activityPrizeDo=activityPrizeMapper.selectByAPId(param.getActivityId(),param.getPrizeId());
        if (null == activityPrizeDo){
            log.info("校验抽奖请求不通过！原因：{}", ServiceErrorCodeConstants.PRIZE_IS_EMPTY.getMsg());
            return false;
        }
        if (activityPrizeDo.getStatus().equalsIgnoreCase(ActivityPrizeStatusEnum.COMPLETED.name())){
            log.info("校验抽奖请求不通过！原因：{}",ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED.getMsg());
            return false;
        }

        //中奖者人数是否和设置奖品数量一致
        if (activityPrizeDo.getPrizeAmount() != param.getWinnerList().size()){
            log.info("校验抽奖请求不通过！原因：{}",ServiceErrorCodeConstants.WINNER_PRIZE_AMOUNT_ERROR.getMsg());
            return false;
        }
        return true;
    }

    @Override
    public List<WinningRecordDO> saveWinnerRecords(DrawPrizeParam param) {

        //查询相关信息
        ActivityDo aDo=activityMapper.selectById(param.getActivityId());
        List<UserDo> uDoList=userMapper.batchSelectByIds(param.getWinnerList().stream()
                .map(DrawPrizeParam.Winner::getUserId).collect(Collectors.toList()));
        PrizeDo pDo=prizeMapper.selectById(param.getPrizeId());
        ActivityPrizeDo apDo=activityPrizeMapper.selectByAPId(param.getActivityId(),param.getPrizeId());

        //构造中奖者信息
        List<WinningRecordDO> wrDoList=uDoList.stream()
                .map(userDo -> {
                    WinningRecordDO wrDo=new WinningRecordDO();
                    wrDo.setWinnerId(userDo.getId());
                    wrDo.setWinnerName(userDo.getUserName());
                    wrDo.setWinnerEmail(userDo.getEmail());
                    wrDo.setWinnerPhoneNumber(userDo.getPhoneNumber());
                    wrDo.setWinningTime(param.getWinningTime());
                    wrDo.setActivityId(apDo.getActivityId());
                    wrDo.setActivityName(aDo.getActivityName());
                    wrDo.setPrizeId(pDo.getId());
                    wrDo.setPrizeName(pDo.getName());
                    wrDo.setPrizeTier(apDo.getPrizeTiers());
                    return wrDo;
                }).collect(Collectors.toList());
        //保存中奖者信息
        winningRecordMapper.batchInsert(wrDoList);

        //缓存中奖者信息
        //1、缓存奖品维度中奖者记录（activityId_prizeId, winningRecordDOList)
        cacheWinningRecords(param.getActivityId()+"_"+param.getPrizeId(),wrDoList,WINNING_RECORDS_TIMEOUT);

        //2、缓存活动维度中奖记录（activityId,allList）
        if (aDo.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())){
            List<WinningRecordDO> allList=winningRecordMapper.selectByActivityId(param.getActivityId());
            cacheWinningRecords(String.valueOf(param.getActivityId()),allList,WINNING_RECORDS_TIMEOUT);
        }
        return wrDoList;
    }

    @Override
    public void deleteRecords(Long activityId, Long prizeId) {
        if (null == activityId){
            log.warn("要删除中奖记录相关的活动id为空！");
            return;
        }
        //删除数据库中相关记录
        winningRecordMapper.deleteRecords(activityId,prizeId);

        //删除缓存
        // 无论是否传递了prizeId，都需要删除活动维度的中奖记录缓存：
        // 如果传递了prizeId, 证明奖品未抽奖，必须删除活动维度的缓存记录
        // 如果没有传递prizeId，就只是删除活动维度的信息
        if (null!=prizeId)
            deleteWinningRecords(activityId+"_"+prizeId);
        deleteWinningRecords(String.valueOf(activityId));
    }

    @Override
    public List<WinningRecordDTO> getRecords(ShowWinningRecordsParm param) {
        //查询redis：奖品、活动
        String key= null==param.getPrizeId()
                ? String.valueOf(param.getActivityId())
                :param.getActivityId()+"_"+param.getPrizeId();
        List<WinningRecordDO> wrDOList=getWinningRecords(key);
        if (!CollectionUtils.isEmpty(wrDOList)) return converToWinningRecordDTOList(wrDOList);

        //如果redis不存在，查库
        wrDOList=winningRecordMapper.selectByActivityIdOrPrizeId(param.getActivityId(), param.getPrizeId());

        //存放记录到redis
        if (CollectionUtils.isEmpty(wrDOList)){
            log.info("查询到的中奖记录为空！param:{}",param);
            return Arrays.asList();
        }
        cacheWinningRecords(key,wrDOList,WINNING_RECORDS_TIMEOUT);
        return converToWinningRecordDTOList(wrDOList);
    }

    private void cacheWinningRecords(String key, List<WinningRecordDO> wrDoList, Long timeout) {
        String str="";
        try {
            if (!StringUtils.hasText(key) || CollectionUtils.isEmpty(wrDoList)){
                log.warn("要缓存的内容为空！key:{},value:{}",key,JacksonUtil.writeValueAsString(wrDoList));
                return;
            }
            str=JacksonUtil.writeValueAsString(wrDoList);
            redisUtil.set(WINNING_RECORDS_PREFIX+key,str,timeout);

        }catch (Exception e){
            log.error("缓存中奖记录异常！key:{},value:{}",WINNING_RECORDS_PREFIX+key,JacksonUtil.writeValueAsString(wrDoList));
        }
    }

    private List<WinningRecordDO> getWinningRecords(String key){
        try{
            if (!StringUtils.hasText(key)){
                log.warn("从缓存中查询中奖信息异常！key为空");
                return Arrays.asList();//返回一个空列表
            }
            String str=redisUtil.get(WINNING_RECORDS_PREFIX+key);
            if (!StringUtils.hasText(str)) return Arrays.asList();
            return JacksonUtil.readListValue(str,WinningRecordDO.class);
        }catch (Exception e){
            log.error("从缓存中查询中奖信息异常！key:{}",WINNING_RECORDS_PREFIX+key);
            return Arrays.asList();
        }
    }

    private List<WinningRecordDTO> converToWinningRecordDTOList(List<WinningRecordDO> wrDOList) {
        if (CollectionUtils.isEmpty(wrDOList)) return Arrays.asList();

        return wrDOList.stream()
                .map( wrDO->{
                    WinningRecordDTO wrDTO =new WinningRecordDTO();
                    wrDTO.setWinnerId(wrDO.getWinnerId());
                    wrDTO.setWinnerName(wrDO.getWinnerName());
                    wrDTO.setPrizeName(wrDO.getPrizeName());
                    wrDTO.setPrizeTier(ActivityPrizeTiersEnum.forName(wrDO.getPrizeTier()));
                    wrDTO.setWinnerTime(wrDO.getWinningTime());
                    return wrDTO;
                }).collect(Collectors.toList());
    }

    private void deleteWinningRecords(String key) {
        try{
            if (redisUtil.hasKey(WINNING_RECORDS_PREFIX+key))
                redisUtil.del(WINNING_RECORDS_PREFIX+key);
        }catch (Exception e){
            log.error("删除中奖记录缓存异常，key:{}",key);
        }
    }
}






























